/*
* Poppy Game Engine - https://pgetemplate.googlecode.com/svn/
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* Copyright (c) 2008 Poppy
*/

#pragma once

#include "MainExportSymbol.h"
#include "SystemDefines.h"

namespace PGEMain
{

	struct CStringWData
	{
		long nRefs;
		int nDataLength;
		int nAllocLength;
		wchar_t* data() { return (wchar_t*)(this+1); }
	};

	class PGEMAIN_API CStringW
	{

	public:

		CStringW();
		CStringW(const CStringW& stringSrc);
		CStringW(wchar_t ch, int nLength =1);
		CStringW(LPCTSTR lpsz);
		CStringW(LPCTSTR lpch, int nLength);
		CStringW(const BYTE* psz);
		~CStringW();

		int GetLength() const;
		int GetAllocLength() const;
		bool IsEmpty() const;
		operator LPCTSTR() const;
		void Empty();

		const CStringW& operator = (const CStringW& stringSrc);
		const CStringW& operator = (LPCTSTR lpsz);
		const CStringW& operator = (wchar_t ch);
		const CStringW& operator += (const CStringW& string);
		const CStringW& operator += (wchar_t ch);
		const CStringW& operator += (LPCTSTR lpsz);
		wchar_t operator [] (int nIndex) const;

		friend CStringW operator + (const CStringW& string1,const CStringW& string2);
		friend CStringW operator + (const CStringW& string, wchar_t ch);
		friend CStringW operator + (wchar_t ch, const CStringW& string);
		friend CStringW operator + (const CStringW& string, LPCTSTR lpsz);
		friend CStringW operator + (LPCTSTR lpsz, const CStringW& string);

		int Delete(int nIndex, int nCount = 1);
		int Insert(int nIndex, wchar_t ch);
		int Insert(int nIndex, LPCTSTR pstr);
		int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew);
		int Replace(wchar_t chOld, wchar_t chNew);
		int Remove(wchar_t chRemove);
		void TrimRight(LPCTSTR lpszTargetList);
		void TrimRight(wchar_t chTarget);
		void TrimRight();
		void TrimLeft(LPCTSTR lpszTargets);
		void TrimLeft(wchar_t chTarget);
		void TrimLeft();

		void SetAt(int nIndex, wchar_t ch);
		wchar_t GetAt(int nIndex) const;
		CStringW Mid(int nFirst) const;
		CStringW Mid(int nFirst, int nCount) const;
		CStringW Right(int nCount) const;
		CStringW Left(int nCount) const;
		void MakeUpper();
		void MakeLower();
		void MakeReverse();

		int Find(wchar_t ch) const;
		int Find(wchar_t ch, int nStart) const;
		int ReverseFind(wchar_t ch) const;
		int Find(LPCTSTR lpszSub) const;
		int Find(LPCTSTR lpszSub, int nStart) const;
		int FindOneOf(LPCTSTR lpszCharSet) const;

		LPTSTR GetBuffer(int nMinBufLength);
		void ReleaseBuffer(int nNewLength=-1);
		LPTSTR GetBufferSetLength(int nNewLength);
		void FreeExtra();
		LPTSTR LockBuffer();
		void UnlockBuffer();
		
		int Compare(LPCTSTR lpsz) const;
		int CompareNoCase(LPCTSTR lpsz) const;
		
		int Collate(LPCTSTR lpsz) const;

		void Format(LPCTSTR lpszFormat, ...);

	protected:

		void Init();
		CStringWData* GetData() const;
		void AllocBuffer(int nLen);
		void CopyBeforeWrite();
		void AllocBeforeWrite(int nLen);
		void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
		
		void AllocCopy(CStringW& dest, int nCopyLen, int nCopyIndex,int nExtraLen) const;
		void Release();

		#ifdef WIN32
		typedef char* psp_va_list;
		#endif
		#ifdef PSP
		typedef void* psp_va_list;
		#endif

		void FormatV(LPCTSTR lpszFormat, psp_va_list argList);
		void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data, int nSrc2Len, LPCTSTR lpszSrc2Data);
		void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);

		static void  Release(CStringWData* pData);
		static void FreeData(CStringWData* pData);
		static int SafeStrlen(LPCTSTR lpsz);
		LPTSTR m_pchData;

	};

	bool PGEMAIN_API operator==(const CStringW& s1, const CStringW& s2);
	bool PGEMAIN_API operator==(const CStringW& s1, LPCTSTR s2);
	bool PGEMAIN_API operator==(LPCTSTR s1, const CStringW& s2);
	bool PGEMAIN_API operator!=(const CStringW& s1, const CStringW& s2);
	bool PGEMAIN_API operator!=(const CStringW& s1, LPCTSTR s2);
	bool PGEMAIN_API operator!=(LPCTSTR s1, const CStringW& s2);
	bool PGEMAIN_API operator<(const CStringW& s1, const CStringW& s2);
	bool PGEMAIN_API operator<(const CStringW& s1, LPCTSTR s2);
	bool PGEMAIN_API operator<(LPCTSTR s1, const CStringW& s2);
	bool PGEMAIN_API operator>(const CStringW& s1, const CStringW& s2);
	bool PGEMAIN_API operator>(const CStringW& s1, LPCTSTR s2);
	bool PGEMAIN_API operator>(LPCTSTR s1, const CStringW& s2);
	bool PGEMAIN_API operator<=(const CStringW& s1, const CStringW& s2);
	bool PGEMAIN_API operator<=(const CStringW& s1, LPCTSTR s2);
	bool PGEMAIN_API operator<=(LPCTSTR s1, const CStringW& s2);
	bool PGEMAIN_API operator>=(const CStringW& s1, const CStringW& s2);
	bool PGEMAIN_API operator>=(const CStringW& s1, LPCTSTR s2);
	bool PGEMAIN_API operator>=(LPCTSTR s1, const CStringW& s2);

	void ConstructElements(CStringW* pElements, int nCount);
	void DestructElements(CStringW* pElements, int nCount);
	void CopyElements(CStringW* pDest, const CStringW* pSrc, int nCount);

}
